package com.yunti.springboot.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.yunti.springboot.bo.UserBO;
import com.yunti.springboot.config.component.AbstractCurrentRequestComponent;
import com.yunti.springboot.mapper.*;
import com.yunti.springboot.po.*;
import com.yunti.springboot.service.UserService;
import com.yunti.springboot.util.JwtUtil;
import com.yunti.springboot.vo.Result;
import com.yunti.springboot.vo.req.*;
import io.jsonwebtoken.Claims;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.time.LocalDateTime;
import java.util.List;
import java.util.Objects;
import java.util.concurrent.TimeUnit;

import static com.yunti.springboot.config.component.AbstractCurrentRequestComponent.TOKEN_KEY;

/**
 * @author luojianguo
 */
@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService {

    @Resource
    UserMapper userMapper;
    @Resource
    DeviceMapper mapper;
    @Resource
    private UserRoleMapper userRoleMapper;
    @Resource
    private DeviceSchoolMapper deviceSchoolMapper;
    @Resource
    private SchoolMapper schoolMapper;

    @Resource
    protected StringRedisTemplate stringRedisTemplate;

    @Resource
    private AbstractCurrentRequestComponent abstractCurrentRequestComponent;

    @Override
    public Result device_login(UserLoginReq userLoginReq) {
        QueryWrapper queryWrapper = new QueryWrapper();
        queryWrapper.eq("device_name",userLoginReq.getUserName());
        Device device = mapper.selectOne(queryWrapper);
        if(device == null){
            return Result.error("用户名或密码错误","用户名或密码错误");
        }

        LambdaQueryWrapper<DeviceSchool> lambdaQueryWrapper = new LambdaQueryWrapper();
        lambdaQueryWrapper.eq(DeviceSchool::getDeviceId,device.getId());
        DeviceSchool deviceSchool = deviceSchoolMapper.selectOne(lambdaQueryWrapper);

        BCryptPasswordEncoder bCryptPasswordEncoder = new BCryptPasswordEncoder();
        if (bCryptPasswordEncoder.matches(userLoginReq.getPassword(),device.getPassword())){
            String token = JwtUtil.createJWT(device.getDeviceName());
            UserBO userBO = new UserBO();
            userBO.setToken(token);
            userBO.setType(2);
            if(deviceSchool!=null)userBO.setSchoolId(deviceSchool.getSchoolId());
            userBO.setRank(userMapper.getAllPermissionById(device.getId()));
            BeanUtils.copyProperties(device,userBO);
//            stringRedisTemplate.opsForValue().set(TOKEN_KEY + user.getUsername(), JSON.toJSONString(userBO),10, TimeUnit.HOURS);
            stringRedisTemplate.opsForValue().set(TOKEN_KEY + device.getDeviceName(), JSON.toJSONString(userBO));
            return Result.success("登录成功",userBO);
        }
        return Result.error("用户名或密码错误","用户名或密码错误");
    }

    @Override
    public Result login(UserLoginReq userLoginReq) {
        System.out.println(userLoginReq);
        QueryWrapper queryWrapper = new QueryWrapper();
        queryWrapper.eq("username",userLoginReq.getUserName());
        User user = userMapper.selectOne(queryWrapper);
        if(user == null){
            return Result.error("用户名不存在","用户名不存在");
        }
        if(!user.getEnable()){
            return Result.error("用户被锁定，请联系管理员","用户被锁定，请联系管理员");
        }
        BCryptPasswordEncoder bCryptPasswordEncoder = new BCryptPasswordEncoder();
        if (bCryptPasswordEncoder.matches(userLoginReq.getPassword(),user.getPassword())){
            School school =  schoolMapper.selectById(user.getSchoolId());
            String token = JwtUtil.createJWT(user.getUsername());
            UserBO userBO = new UserBO();
            userBO.setToken(token);
            userBO.setType(1);
            if(school != null){
                userBO.setSchoolName(school.getName());
            }
            userBO.setRank(userMapper.getAllPermissionById(user.getId()));
            BeanUtils.copyProperties(user,userBO);
//            stringRedisTemplate.opsForValue().set(TOKEN_KEY + user.getUsername(), JSON.toJSONString(userBO),10, TimeUnit.HOURS);
            stringRedisTemplate.opsForValue().set(TOKEN_KEY + user.getUsername(), JSON.toJSONString(userBO));
            return Result.success("登录成功",userBO);
        }
        return Result.error("用户名或密码错误","用户名或密码错误");
    }

    @Transactional(rollbackFor = Exception.class,propagation = Propagation.REQUIRED)
    @Override
    public Result updateUserById(UpdateUserReq updateUserReq) {
        if(Objects.isNull(updateUserReq)){
            return Result.error("参数不能为空！");
        }
        if(updateUserReq.getRole() != null && updateUserReq.getRole().length == 0){
            return Result.error("","编辑失败！权限不能为空");
        }
        User user = new User();
        user.setId(updateUserReq.getId())
                .setNickname(updateUserReq.getNickName())
                .setPhone(updateUserReq.getPhone());
        if(updateUserReq.getSchoolId() != null){
            user.setSchoolId(updateUserReq.getSchoolId());
        }
        if(userMapper.updateById(user) >0){
           String [][] roles = updateUserReq.getRole();
           if(roles.length>0){
               QueryWrapper<UserRole> queryWrapper = new QueryWrapper<>();
               queryWrapper.eq("user_id",updateUserReq.getId());
               userRoleMapper.delete(queryWrapper);
               for (int i = 0; i < roles.length; i++) {
                   UserRole userRole = new UserRole();
                   userRole.setUserId(updateUserReq.getId())
                           .setRoleId(Integer.valueOf(roles[i][0]))
                           .setCreateTime(LocalDateTime.now())
                           .setUpdateTime(LocalDateTime.now());
                   userRoleMapper.insert(userRole);
               }
           }
        }
        return Result.success("更新成功");
    }

    @Override
    public Result getUserListPage(UserSearchReq userSearchReq) {
        if (userSearchReq.getCurrent() == null) {
            userSearchReq.setCurrent(0);
        }
        if (userSearchReq.getSize() == null) {
            userSearchReq.setSize(10);
        }
        UserBO userBO = abstractCurrentRequestComponent.getCurrentStaffId();
        userSearchReq.setSchoolId(userBO.getSchoolId());
        Page page = new Page<>(userSearchReq.getCurrent(), userSearchReq.getSize());
        return Result.success(page.setRecords(userMapper.getUserListPage(userSearchReq,page)));
    }

    @Override
    public Result updatePassword(UpdatePasswordReq updatePasswordReq) {
        UserBO userBO = abstractCurrentRequestComponent.getCurrentStaffId();
        BCryptPasswordEncoder bCryptPasswordEncoder = new BCryptPasswordEncoder();
        if (bCryptPasswordEncoder.matches(updatePasswordReq.getOldPassword(),userBO.getPassword())){
            User user = new User()
                    .setId(userBO.getId())
                    .setNickname(updatePasswordReq.getNickName())
                    .setPassword(bCryptPasswordEncoder.encode(updatePasswordReq.getNewPassword()));
            if(userMapper.updateById(user)>0){
                return Result.success("更改成功！请重新登录","更改成功！请重新登录");
            }else {
                return Result.error("更改失败！用户不存在","更改失败！用户不存在");
            }

        }else {
            return Result.error("更改失败！密码错误","更改失败！密码错误");
        }
    }

    @Override
    public Result updateNickName(UpdateNickNameReq updateNickNameReq) {
        UserBO userBO = abstractCurrentRequestComponent.getCurrentStaffId();
        User user = new User()
                .setId(userBO.getId())
                .setNickname(updateNickNameReq.getNewNickName());
        if(userMapper.updateById(user)>0){
            return Result.success("更改成功！","更改成功！");
        }else {
            return Result.error("更改失败！用户不存在","更改失败！用户不存在");
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class,propagation = Propagation.REQUIRED)
    public Result register(RegisterParmReq registerParm) {
        if(Objects.isNull(registerParm)){
            return Result.error("参数不能为空！");
        }
        List<User>list = userMapper.selectList(new LambdaQueryWrapper<User>().eq(User::getUsername,registerParm.getUserName()));
        if(list.size()>0){
            return Result.error("","新增失败！用户已存在");
        }
        if(registerParm.getRole() != null && registerParm.getRole().length == 0){
            return Result.error("","新增失败！权限不能为空");
        }
        UserBO userBO = abstractCurrentRequestComponent.getCurrentStaffId();
        User newUser = new User();
        BCryptPasswordEncoder bCryptPasswordEncoder = new BCryptPasswordEncoder();
        newUser.setUsername(registerParm.getUserName())
                .setNickname(registerParm.getNickName())
                .setPassword(bCryptPasswordEncoder.encode(registerParm.getPassword()))
                .setEnable(true)
                .setParentId(userBO.getId())
                .setPhone(registerParm.getPhone())
                .setCreateTime(LocalDateTime.now());
        //学校id 管理员指定，小程序教师使用教ID
        if(registerParm.getSchoolId()==null){
            newUser.setSchoolId(userBO.getSchoolId());
        }else {
            newUser.setSchoolId(registerParm.getSchoolId());
        }
        int col = userMapper.saveUser(newUser);
        // 如果插入user成功,进行userrole表操作
        if(col == 1){
            String roles = "";
            String [][] getRoles = registerParm.getRole();
            for (int i = 0; i < getRoles.length; i++) {
                UserRole userRole = new UserRole();
                userRole.setUserId(newUser.getId())
                        .setRoleId(Integer.valueOf(getRoles[i][0]))
                        .setCreateTime(LocalDateTime.now())
                        .setUpdateTime(LocalDateTime.now());
                userRoleMapper.insert(userRole);
            }
        }else {
            return Result.error("新增失败！");
        }
        return Result.success("新增用户成功！");
    }

    @Override
    public Result deleteUser(Integer id) {
        if(Objects.isNull(id)){
            return Result.error("缺少必要参数！");
        }
        int success = userMapper.deleteById(id);
        if(success == 1){
            return Result.success("删除成功！");
        }else {
            return Result.error("删除失败！");
        }
    }

    @Override
    public Result getChildrenUserList(UserSearchReq userSearchReq) {
        if (userSearchReq.getCurrent() == null) {
            userSearchReq.setCurrent(0);
        }
        if (userSearchReq.getSize() == null) {
            userSearchReq.setSize(10);
        }
        UserBO userBO = abstractCurrentRequestComponent.getCurrentStaffId();
        userSearchReq.setParentId(userBO.getId());
        Page page = new Page<>(userSearchReq.getCurrent(), userSearchReq.getSize());
        return Result.success(page.setRecords(userMapper.getChildrenUserListPage(userSearchReq,page)));
    }

    @Override
    public Result getLoginInfo() {
        UserBO userBO = abstractCurrentRequestComponent.getCurrentStaffId();
        return Result.success(userBO);
    }

    @Override
    public Result changSwitch(Integer id, String type) {
        if(Objects.isNull(id) || "".equals(type)){
            return Result.error("缺少必要参数！");
        }
        User u = new User();
        u.setId(id).setEnable(Boolean.valueOf(type));
        if(userMapper.updateById(u)>0){
            return Result.success("修改状态成功！");
        }
        return Result.error("修改状态失败！");
    }

    @Override
    public Result checkLogin(String token) {
        Claims claims = null;
        try {
            claims = JwtUtil.parseJWT(token);
        } catch (Exception e) {
            return Result.success(false);
        }
        if (claims == null){
            return Result.success(false);
        }
        String userName = String.valueOf(claims.getSubject());
        String result = stringRedisTemplate.opsForValue().get(TOKEN_KEY + userName);
        if (StringUtils.isNotBlank(result)) {
            UserBO oaUserBO = JSONObject.parseObject(result, UserBO.class);
            if (oaUserBO == null) {
                return Result.success(false);
            }
            oaUserBO.setToken(token);
            return Result.success(true);
        }
        return Result.success(false);
    }
}
